using DA.AnimGraph;
using System;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
using static UnityEditor.Experimental.GraphView.Port;

namespace DA.AnimGraph.Editor {
    internal class BlendTreePort : Port {
        private readonly AGEEnvironment ageEnv;

        public AUID uuid { get; private set; }
        //AnimGraphView graphView;

        public BlendTreePort(AnimGraphView graphView, AGEEnvironment ageEnv, AUID uuid, Orientation portOrientation, Direction portDirection, Capacity portCapacity, Type type)
            : base(portOrientation, portDirection, portCapacity, type) {

            this.ageEnv = ageEnv;
            //this.graphView = graphView;
            this.uuid = uuid;

            var btCanvas = graphView.GetFirstAncestorOfType<BlendTreeCanvas>();
            m_EdgeConnector = new BTEdgeConnector(new EdgeConnectorListener(btCanvas, ageEnv), ageEnv);
            this.AddManipulator(m_EdgeConnector);
        }
    }

    class BTEdgeConnector : EdgeConnector<BlendTreeEdge> {
        private readonly AGEEnvironment ageEnv;

        public BTEdgeConnector(IEdgeConnectorListener listener, AGEEnvironment ageEnv) : base(listener) {
            this.ageEnv = ageEnv;
        }
        protected override void OnMouseDown(MouseDownEvent e) {
            if (ageEnv.ageMode == AGEMode.Edit) {
                base.OnMouseDown(e);
            }
        }
    }

    class EdgeConnectorListener : IEdgeConnectorListener {
        private readonly BlendTreeCanvas btCanvas;
        private readonly AGEEnvironment ageEnv;

        private GraphViewChange m_GraphViewChange;

        private List<Edge> m_EdgesToCreate;

        private List<Edge> m_EdgesToDelete;

        public EdgeConnectorListener(BlendTreeCanvas btCanvas, AGEEnvironment ageEnv) {
            this.btCanvas = btCanvas;
            this.ageEnv = ageEnv;

            m_EdgesToCreate = new List<Edge>();
            m_EdgesToDelete = new List<Edge>();
            m_GraphViewChange.edgesToCreate = m_EdgesToCreate;
        }

        public void OnDrop(GraphView graphView, Edge edge) {

            if (IsConnectedTo(edge.output, edge.input, edge)) {
                //避免重复连线的二次保险
                return;
            }

            m_EdgesToCreate.Clear();
            m_EdgesToCreate.Add(edge);
            m_EdgesToDelete.Clear();
            if (edge.input.capacity == Capacity.Single) {
                foreach (Edge connection in edge.input.connections) {
                    if (connection != edge) {
                        m_EdgesToDelete.Add(connection);
                    }
                }
            }

            if (edge.output.capacity == Capacity.Single) {
                foreach (Edge connection2 in edge.output.connections) {
                    if (connection2 != edge) {
                        m_EdgesToDelete.Add(connection2);
                    }
                }
            }

            if (m_EdgesToDelete.Count > 0) {
                btCanvas.DeleteEdgesData(m_EdgesToDelete);
                graphView.DeleteElements(m_EdgesToDelete);
            }
            btCanvas.AddEdgesData(m_EdgesToCreate);

            List<Edge> edgesToCreate = m_EdgesToCreate;
            if (graphView.graphViewChanged != null) {
                edgesToCreate = graphView.graphViewChanged(m_GraphViewChange).edgesToCreate;
            }

            foreach (Edge item in edgesToCreate) {
                graphView.AddElement(item);
                edge.input.Connect(item);
                edge.output.Connect(item);
            }

        }

        public void OnDropOutsidePort(Edge edge, Vector2 position) {
            // todo:提供一种删除方式

        }

        bool IsConnectedTo(Port startPort, Port endPort, Edge exceptEdge = null) {
            foreach (var edge in startPort.connections) {
                if (edge.output == startPort && edge.input == endPort) {
                    if (edge != exceptEdge) {
                        return true;
                    }
                }
            }
            return false;
        }
    }
}
